package com.uuah.server.config.spring.parsers.processors;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;

import com.uuah.server.config.spring.parsers.PreProcessor;
import com.uuah.server.config.spring.parsers.assembly.configuration.IPropertyConfiguration;
import com.uuah.server.util.spring.SpringXMLUtils;

/**
 * All attributes from at least one set must be provided
 */
public class CheckRequiredAttributes implements PreProcessor {

	// maps from attribute name to attribute set index (integer)
	private Map knownAttributes = new HashMap();
	// maps from attribute set index to number of attributes in that set
	private Map numberOfAttributes = new HashMap();
	// description of acceptable attributes
	private String summary;

	public CheckRequiredAttributes(String[][] attributeSets) {
		StringBuffer buffer = new StringBuffer();
		for (int set = 0; set < attributeSets.length; set++) {
			String[] attributes = attributeSets[set];
			// ignore empty sets
			if (attributes.length > 0) {
				Integer index = new Integer(set);
				numberOfAttributes.put(index, new Integer(attributes.length));
				if (set > 0) {
					buffer.append("; ");
				}
				for (int attribute = 0; attribute < attributes.length; attribute++) {
					knownAttributes.put(attributes[attribute], index);
					if (attribute > 0) {
						buffer.append(", ");
					}
					// don't translate to alias because the error message is in
					// terms of the attributes
					// the user enters - we don't want to expose the details of
					// translations
					buffer.append(attributes[attribute]);
				}
			}
		}
		summary = buffer.toString();
	}

	public void preProcess(IPropertyConfiguration config, Element element) {
		// map from attribute set index to count
		Map foundAttributesCount = new HashMap();

		NamedNodeMap attributes = element.getAttributes();
		for (int i = 0; i < attributes.getLength(); i++) {
			String alias = SpringXMLUtils.attributeName((Attr) attributes
					.item(i));
			if (knownAttributes.containsKey(alias)) {
				Integer index = (Integer) knownAttributes.get(alias);
				if (!foundAttributesCount.containsKey(index)) {
					foundAttributesCount.put(index, new Integer(0));
				}
				foundAttributesCount.put(index, new Integer(
						1 + ((Integer) foundAttributesCount.get(index))
								.intValue()));

			}
		}

		// if there are no attributes to check for, we are ok
		boolean ok = knownAttributes.size() == 0;
		Iterator indices = foundAttributesCount.keySet().iterator();
		while (indices.hasNext() && !ok) {
			Object index = indices.next();
			Object count = foundAttributesCount.get(index);
			ok = numberOfAttributes.get(index).equals(count);
		}
		if (!ok) {
			throw new CheckRequiredAttributesException(element, summary);
		}
	}

	public static class CheckRequiredAttributesException extends
			IllegalStateException {

		private CheckRequiredAttributesException(Element element, String summary) {
			super("Element " + SpringXMLUtils.elementToString(element)
					+ " must have all attributes for one of the sets: "
					+ summary + ".");
		}

	}

}
